#include <iostream>
#include "Slave.h"
#include <mpi.h>

#include <unistd.h> // sleep()

using namespace std;


class MySlave : public Slave{

	public:		
		void JobHandler(char* inputBuffer, int size){
			printf("->Rank%d Operacja: Otrzymano znak %c\n", slaveId, *inputBuffer);
			printf("->Rank%d Operacja: Cos tam robie przez 5 sekund...\n", slaveId);
			sleep(5);
			// for(;;) ;
		}
		
};

class MySlave2 : public Slave{
	
	public:
		void JobHandler(char* inputBuffer, int size)
		{
			printf("->Rank%d Operacja: A ja cos zrobie w 10 sekund...\n", slaveId);
			sleep(10);
		}
		
};


int main(int argc, char *argv[]){
	int pool_size, my_rank;

	MPI_Init(&argc, &argv);
	MPI_Comm_size(MPI_COMM_WORLD, &pool_size);
	MPI_Comm_rank(MPI_COMM_WORLD, &my_rank);
	
	printf("Initialized node: %d of %d\n", my_rank, pool_size);

	// poki co, testowe wyslanie 	
	if (my_rank==0){
		MPI_Request request;
		MPI_Status status;
		
		char jobBuffer[1024];
		int tag = TAG_JOB;
		jobBuffer[0] = 'x'; // przykladowa wiadomosc
		
		printf("MASTER: buffer[0] = %c\n", jobBuffer[0]);
		
		for(int i=1; i<pool_size; i++){
			printf("MASTER: TAG_JOB do %d\n", i);
			MPI_Isend (jobBuffer, sizeof(jobBuffer), MPI_CHAR,
					   i, tag, MPI_COMM_WORLD, &request);
			MPI_Wait (&request, &status);
		}
		
		
		// SetBufferSize
		tag = TAG_SET_BUFFER_SIZE;
		int newSize = 2048;
		memcpy(jobBuffer, &newSize, 4);
		
		for(int i=1; i<pool_size; i++){
			printf("MASTER: SET_BUFFER_SIZE do %d\n", i);
			MPI_Isend (jobBuffer, sizeof(jobBuffer), MPI_CHAR,
					   i, tag, MPI_COMM_WORLD, &request);
			MPI_Wait (&request, &status);
		}
		
		
		// Reset BufferSize
		tag = TAG_RESET_BUFFER_SIZE;
		for(int i=1; i<pool_size; i++){
			printf("MASTER: RESET_BUFFER_SIZE do %d\n", i);
			MPI_Isend (jobBuffer, sizeof(jobBuffer), MPI_CHAR,
					   i, tag, MPI_COMM_WORLD, &request);
			MPI_Wait (&request, &status);
		}
		
		// odebranie wynikow		
		for(int i=1; i<pool_size; i++){
			int flag;
			int probeFrom;
			
			printf("MASTER: Probing...\n");
			for(;;){
				MPI_Iprobe(MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &flag, &status);
				if (flag==1){
					probeFrom = status.MPI_SOURCE;
					printf("MASTER: Flag = 1\n");
					break;
				}
			}
			
			printf("MASTER: Receiving TAG_JOB %d\n", i);
			MPI_Irecv (jobBuffer, sizeof(jobBuffer), MPI_CHAR, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD,
						   &request);
			MPI_Wait (&request, &status);			
			printf("MASTER: Received %d!\n", jobBuffer[0]);
		}
		
		tag = TAG_TERMINATE_SLAVE;
		for(int i=1; i<pool_size; i++){
			printf("MASTER: Sending TAG_TERMINATE_SLAVE to %d\n", i);
			MPI_Isend (jobBuffer, sizeof(jobBuffer), MPI_CHAR,
					   i, tag, MPI_COMM_WORLD, &request);
			MPI_Wait (&request, &status);
		}
		
	}
	
	if (my_rank==1){
		MySlave2* mySlave2 = new MySlave2();
		mySlave2->SetParameters(my_rank, 1024);
		mySlave2->Start();
	}
	
	// Slaves
	if (my_rank>1){
		MySlave* mySlave = new MySlave();
		mySlave->SetParameters(my_rank, 1024);
		mySlave->Start();
	}
		
	MPI_Finalize();
}
